package org.example.sys.config;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ConfigurationBuilder;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Set;

/**
 * 这里的@OpenAPIDefinition 和@SecurityScheme都是springdoc注解，主要声明API信息：标题、版本、许可证、安全性、服务器、标签、安全性和拓展文档信息。
 * 配置jwt时，@SecurityScheme(type = SecuritySchemeType.HTTP, name = “JWT”, scheme = “bearer”, in = SecuritySchemeIn.HEADER).scheme 还支持basic。
 * 具体可查看官网文档: https://springdoc.org/index.html
 * 示例：https://www.cnblogs.com/breezefaith/p/17998698
 * @Api -> @Tag
 * @ApiIgnore -> @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
 * @ApiImplicitParam -> @Parameter
 * @ApiImplicitParams -> @Parameters
 * @ApiModel -> @Schema
 * @ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY)
 * @ApiModelProperty -> @Schema
 * @ApiOperation(value = "foo", notes = "bar") -> @Operation(summary = "foo", description = "bar")
 * @ApiParam -> @Parameter
 * @ApiResponse(code = 404, message = "foo") -> @ApiResponse(responseCode = "404", description = "foo")
 */
@Slf4j
@OpenAPIDefinition(security = @SecurityRequirement(name = "Authorization"))
@SecurityScheme(type = SecuritySchemeType.APIKEY, name = "Authorization", scheme = "Authorization", in = SecuritySchemeIn.HEADER)
@Configuration
public class SpringDocConfig {

    private String title = "Calvin";//标题
    private String group = "group";//分组名称
    private String description = "被你捧做神明的人，怎会低头看尘埃里的你";//简介
    private String version = "ver_1.0.0";//版本
    private String termsOfService = "XXX";//服务Url
    private String contactName = "Calvin";//作者

    //@Resource
    //@Value(value = "${spring.application.controller.packages}")
    String[] controllerPackages;


    /**
     * 添加全局的请求头参数
     */
    @Bean
    public OpenApiCustomiser customerGlobalHeaderOpenApiCustomiser() {
        return openApi -> openApi.getPaths().values().stream().flatMap(pathItem -> pathItem.readOperations().stream())
                .forEach(operation -> {
                    operation.addParametersItem(new HeaderParameter().$ref("#/components/parameters/myGlobalHeader"));
                });
    }

    @Bean
    public OpenAPI springOpenAPI() {
        //配置认证、请求头参数
        Components components = new Components();
        components.addParameters("token", new HeaderParameter().required(true).name("token").schema(new StringSchema()).required(true))
                .addParameters("username", new HeaderParameter().required(true).name("username").schema(new StringSchema()).required(true));
        // 接口调试路径
        Server tryServer = new Server();
        tryServer.setUrl("http://localhost:8081");
        return new OpenAPI()
                .components(components)
                .servers(Collections.singletonList(tryServer))
//                // 设置 spring security jwt accessToken 认证的请求头 Authorization: Bearer xxx.xxx.xxx
//                .addSecuritySchemes("openApiSecurityScheme", new SecurityScheme().type(SecurityScheme.Type.HTTP)
//                .bearerFormat("JWT")
//                .in(SecurityScheme.In.HEADER)
//                .name("Authorization")
//                .scheme("Bearer")))
                .info(getInfo())
                .externalDocs(new ExternalDocumentation()
                        .description("SpringDoc Full Documentation")
                        .url("https://springdoc.org/"));
    }

    public Info getInfo() {
        return new Info()
                .title(title)
                .description(description)
                .version(version)
                .termsOfService(termsOfService)
                .license(buildLicense())
                .contact(buildContact());
    }

    public Contact buildContact() {
        return new Contact()
                .name(contactName)
                .email("2286704940@qq.com")//Your API Contact Email
                .url("https://XXX");//Your API Contact URL
    }

    public License buildLicense() {
        return new License()
                .name("APACHE LICENSE, VERSION 2.0")//许可证
                .url("https://www.apache.org/licenses/LICENSE-2.0.html");
    }

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group(group)
                .pathsToMatch("/pet/**")//API路径，不是类路径

                //这里是添加对应标签
                .addOpenApiCustomiser(openApi -> {
                    Tag staffTag = new Tag();
                    staffTag.setName("myController");//标签名称
                    staffTag.setDescription("验证一下所有Controller");//描述
                    // 指定某个包中的所有controller
                    String packagePath = "com.data.ant.design.system.controller";
                    Set<Class<?>> controllerClasses = getControllerClasses(packagePath);
                    for (Class<?> controllerClass : controllerClasses) {
                        String controllerName = controllerClass.getSimpleName();
                        staffTag.addExtension("x-controller-" + controllerName, controllerClass.getName());
                    }
                    // 指定单独的controller
//                    String controllerName = "YourControllerName";
//                    Class<?> controllerClass = getControllerClass(packagePath, controllerName);
//                    if (controllerClass != null) {
//                        staffTag.addExtension("x-controller-" + controllerName, controllerClass.getName());
//                    }
                    if (null != openApi.getTags()){
                        openApi.getTags().add(staffTag);
                    } else {
                        openApi.addTagsItem(staffTag);//添加标签
                    }
                })
                .build();
    }

    //显式地配置扫描器
    private Reflections reflectionsConf(String packagePath){
        return new Reflections(new ConfigurationBuilder()
                .forPackages(packagePath)
                .addScanners(new SubTypesScanner()));
    }

    // 获取某个包中的所有controller类
    private Set<Class<?>> getControllerClasses(String packagePath) {
        Reflections reflections = reflectionsConf(packagePath);
        return reflections.getTypesAnnotatedWith(RestController.class);
    }

    // 获取单独的controller类
    private Class<?> getControllerClass(String packagePath, String controllerName) {
        Reflections reflections = reflectionsConf(packagePath);
        Set<Class<?>> controllerClasses = reflections.getTypesAnnotatedWith(RestController.class);
        for (Class<?> controllerClass : controllerClasses) {
            if (controllerClass.getSimpleName().equals(controllerName)) {
                return controllerClass;
            }
        }
        return null;
    }

}

